﻿// UmtlTest.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
//

//#include <umtl/umtl.h>

#include "stdafx.h"

#include <umtl/umtl.h>

#include <iostream>

#include <boost/timer.hpp>

#include <sstream>
#include <fstream>

#include <math.h>

#include <windows.h>
#include <omp.h>
#include <boost/thread.hpp>

#include "../test.h"

#include <boost/asio/windows/random_access_handle.hpp>

namespace
{
	template< typename Type >
	umtl::smart_ptr<Type> make_smart_ptr( Type* p )
	{
		return std::move( umtl::smart_ptr< Type >(p) );
	}
}

/*
struct NormalAlloc
{
	static void * alloc( size_t size )
	{
		return malloc(size);
	}

	static void dealloc( void * p )
	{
		free( p );
	}
};

struct PoolAlloc
{
	static void * alloc( size_t size )
	{
		return umtl::memory_manager::get().alloc( size );
	}

	static void dealloc( void * p )
	{
		umtl::memory_manager::get().free( p );
	}
};

template< typename Allocator, int count >
void alloc_test( int loop = 100000, size_t max_buffer = 1024*512 )
{
	//#pragma omp parallel for schedule(guided)
	for( int i=0; i<loop; ++i )
	{
		void*p[count];

		for( int j=0; j<count; ++j )
			p[j] = Allocator::alloc( max_buffer );
			//p[j] = Allocator::alloc( (rand() % max_buffer) + 1 );

		for( int j=0; j<count; ++j )
			Allocator::dealloc(p[j]);
	}
}

template< typename T >
struct smart_ptr : std::tr1::shared_ptr<T>
{
	typedef std::tr1::shared_ptr<T> shared_ptr;

	smart_ptr(T * t) : shared_ptr(t) {}
};

template< typename Key, typename Value >
struct map : std::map< Key, Value >
{
public:
	umtl::unit_pool_map< Key, map<Key, Value> > member;
};

class TestClass
{
public:
	~TestClass()
	{
		std::cout <<"소멸자" << std::endl;
	}
};

//#include "UmtlTest/test2.h"

template<typename T>
T func( T t )
{
	T tt = t;

	return t;
}

#include <boost/coroutine/coroutine.hpp>
#include <sstream>

#include "umtl/stack_allocator/stack_allocator.h"

template< typename char_t >
struct stringstream_t
{
	typedef std::basic_stringstream< char_t, std::char_traits<char_t>, umtl::stack_allocator<char_t> > type;
};

template< typename char_t >
struct string_t
{
	typedef std::basic_string< char_t, std::char_traits<char_t>, umtl::stack_allocator<char_t> > type;
};

void test11()
{
	static const size_t loop = 10000;

	static const size_t maxsize = 10000;

	boost::timer t;

	for( size_t i = 0; i<loop; ++i )
	{
		char * p = (char*)(_malloca( (rand()%maxsize) + 1 ));
		_freea(p);
	}

	std::cout << t.elapsed() << std::endl;
}
*/

int _tmain(int argc, _TCHAR* argv[])
{
	/*
	typedef umtl::map_tree< std::string, int > map_tree;
	map_tree m;

	m["h"] = 1;

	m.for_each(
		[]( map_tree::value_t & val )
		{
			std::cout << val << std::endl;
		}
	);
	*/

	/*
	char * test = "동해물과백두산이마르고닳도록하느님이보우하사우리나라만세무궁화삼천리화려강산대한사람대한으로길이보전하세동해물과백두산이마르고닳도록하느님이보우하사우리나라만세무궁화삼천리화려강산대한사람대한으로길이보전하세동해물과백두산이마르고닳도록하느님이보우하사우리나라만세무궁화삼천리화려강산대한사람대한으로길이보전하세동해물과백두산이마르고닳도록하느님이보우하사우리나라만세무궁화삼천리화려강산대한사람대한으로길이보전하세동해물과백두산이마르고닳도록하느님이보우하사우리나라만세무궁화삼천리화려강산대한사람대한으로길이보전하세동해물과백두산이마르고닳도록하느님이보우하사우리나라만세무궁화삼천리화려강산대한사람대한으로길이보전하세동해물과백두산이마르고닳도록하느님이보우하사우리나라만세무궁화삼천리화려강산대한사람대한으로길이보전하세동해물과백두산이마르고닳도록하느님이보우하사우리나라만세무궁화삼천리화려강산대한사람대한으로길이보전하세동해물과백두산이마르고닳도록하느님이보우하사우리나라만세무궁화삼천리화려강산대한사람대한으로길이보전하세무궁화삼천리화려강산대한a";

	size_t testLen = strlen(test);

	char test2[176] = {0,};

	umtl::nemo n;

	n.encode( (unsigned char*)test, (unsigned char*)test2 );

	char * test3 = new char[ 512 ];

	memset( test3, 0, 512 );

	boost::timer t;

	n.decode( (unsigned char*)test2, (unsigned char*)test3 );

	std::cout << test3 << std::endl;

	std::cout << (t.elapsed() * 0.001f) << std::endl;
	*/

	/*
	umtl::spack sp( L"test.sp", L"1234" );
	
	//for( int i=0; i<10; ++i )
	{
		sp.addFile( L"ini/data.dat" );
		sp.addFile( L"ini/data2.dat" );
		sp.addFile( L"ini/data3.dat" );
		sp.addFile( L"ini/test.wmv" );
		sp.addFile( L"ini/test.ini" );

		sp.exportFile( L"ini/test.ini", L"ini2/test.ini" );
		sp.exportFile( L"ini/data.dat", L"ini2/data.dat" );
		sp.exportFile( L"ini/data2.dat", L"ini2/data2.dat" );
		sp.exportFile( L"ini/data3.dat", L"ini2/data3.dat" );
		sp.exportFile( L"ini/test.wmv", L"ini2/test.wmv" );
	}
	*/

	/*
	int a[60240];

	boost::timer t;

	t.restart();

	for( int j=0; j<10000; ++j )
	{
		for( int i=0; i < sizeof(a)/sizeof(int); ++i )
		{
			a[i] = (int)pow( (double)i, 10 );
			//a[i] = i;
		}
	}

	std::cout << t.elapsed() << std::endl;

	t.restart();

	for( int j=0; j<10000; ++j )
	{
		umtl::parallel::_for( 0, sizeof(a)/sizeof(int),
			[&a]( int i, bool & breakFlag )
			{
				a[i] = (int)pow( (double)i, 10 );
				//a[i] = i;
			}
		, 0);
	}

	std::cout << t.elapsed() << std::endl;	
	*/

	/*umtl::server server( 11001
		, []( umtl::tcp_connection::pointer connection )
		{
			connection->send( "ok", 3 );
		}
		, []( umtl::tcp_connection * conn, char const * packet, size_t size )
		{
			conn->send( packet, size );
		}
		, 11002
		, []( umtl::udp_connection * conn, char const * packet, size_t size )
		{
			conn->send( packet, size );
		}
	);*/

	/*
	std::tr1::shared_ptr< umtl::tcp_server > tcp_server;

	umtl::parallel::thread input_thread(
		[&tcp_server]()
		{
			std::string line;
			while( line != "exit" )
			{
				std::cin >> line;
				tcp_server->send( line.c_str(), line.length() );
			}
		}
	);

	tcp_server.reset( new umtl::tcp_server ( 11001
			, []( umtl::tcp_connection* conn )
			{
				conn->send( "ok", 3 );
			}
			, [&tcp_server]( umtl::tcp_connection * conn, char const * packet, size_t size )
			{
				std::string msg(packet, size);

				std::stringstream msgStream;

				msgStream << conn << " >> " << msg;

				msg = msgStream.str();

				std::cout << msg << std::endl;

				umtl::tcp_connections connections = tcp_server->connections();

				std::for_each( connections->begin(), connections->end(), 
					[conn, &msg]( umtl::tcp_connections::connection_ptr const & connection )
					{
						if( conn != connection.get() )
						{
							connection->send( msg.c_str(), msg.length() );
						}
					}
				);
			}
			, []( umtl::tcp_connection * conn )
			{
			}
		)
	);
	*/
	
	/*
	umtl::tcp_client client( "127.0.0.1", "11001"
		, []( umtl::tcp_connection * conn, char const * packet, size_t size )
		{
			std::cout << packet << std::endl;
			//conn->send( packet, size );
		}
		, []( umtl::tcp_connection * conn )
		{
		}
	);

	std::string line;

	while( line != "exit" )
	{
		std::cin >> line;
		client.send( line.c_str(), line.length() );
	}
	*/

/*
	std::tr1::shared_ptr< umtl::udp_server > udp_server;

	umtl::parallel::thread input_thread(
		[&udp_server]()
		{
			std::string line;
			while( line != "exit" )
			{
				std::cin >> line;
				udp_server->send( line.c_str(), line.length() );
			}
		}
	);

	udp_server.reset( new umtl::udp_server ( 13
			, [&udp_server]( umtl::udp_connection * conn, char const * packet, size_t size )
			{
				std::string msg(packet, size);

				std::stringstream msgStream;

				msgStream << conn << " >> " << msg;

				msg = msgStream.str();

				std::cout << msg << std::endl;

				umtl::udp_server::connectionProxy connections = udp_server->getConnections();

				std::for_each( connections->begin(), connections->end(), 
					[conn, &msg]( umtl::udp_server::connections::value_type const & connection )
					{
						if( conn != connection.second.get() )
						{
							connection.second->send( msg.c_str(), msg.length() );
						}
					}
				);
			}
			, []( umtl::udp_server::connection * conn )
			{}
		)
	);
	*/

/*
	umtl::udp_client client( "127.0.0.1", "13"
		, []( umtl::udp_connection * conn, char const * packet, size_t size )
		{
			std::string msg(packet, size);
			std::cout << msg << std::endl;
		}
		, []( umtl::udp_connection * conn )
		{}
	);

	std::string line;

	while( line != "exit" )
	{
		std::cin >> line;
		client.send( line.c_str(), line.length() );
	}
	*/

	/*
	static int const count = 58676536;

	int * a = new int[count];

	for( size_t c=0; c<100; ++c )
	{
		boost::timer t;

		umtl::parallel::_for( 0, count, [a](int i, bool & flag){ a[i] = (int)pow((double)i,3); } );
		std::cout << t.elapsed() << std::endl;
		
		// 	for( int i=0; i<count; ++i )
		// 	{
		// 		if( a[i] == i )
		// 			std::cout << i << std::endl;
		// 	}

		t.restart();

		for( int i=0; i<count; ++i )
		{
			a[i] = (int)pow((double)i,3);
			//a[i] = i;
		}

		std::cout << t.elapsed() << std::endl;
	}

	delete[] a;
	*/

/*
	static size_t const loop = 100000;
	static size_t max_size = 65535;
	static size_t max_count = 10;

	{
		char **p = (char**)umtl::memory_manager::get().alloc( max_count * sizeof(char*) );

		for( size_t c=0; c<max_count; ++c )
			p[c] = (char*)umtl::memory_manager::get().alloc( max_size );

		for( size_t c=0; c<max_count; ++c )
			umtl::memory_manager::get().free( p[c] );

		umtl::memory_manager::get().free( p );
	}

	srand( (int)time(0) );

	boost::timer t;

	for( int l = 0; l<3; ++l )
	{
		t.restart();

		for( size_t i=0; i<loop; ++i )
		{
			size_t need_size = (rand() % max_size) + 1;
			size_t need_count = (rand() % max_count) + 1;

			char ** p = new char*[need_count];

			for( size_t c=0; c<need_count; ++c )
				p[c] = new char[ need_size ];

			for( size_t c=0; c<need_count; ++c )
				delete [] p[c];

			delete [] p;
		}

		std::cout << "normal alloc : " << t.elapsed() << std::endl;

		t.restart();

		for( size_t i=0; i<loop; ++i )
		{
			size_t need_size = (rand() % max_size) + 1;
			size_t need_count = (rand() % max_count) + 1;

			char **p = (char**)umtl::memory_manager::get().alloc( need_count * sizeof(char*) );

			for( size_t c=0; c<need_count; ++c )
				p[c] = (char*)umtl::memory_manager::get().alloc( need_size );

			for( size_t c=0; c<need_count; ++c )
				umtl::memory_manager::get().free( p[c] );

			umtl::memory_manager::get().free( p );
		}

		std::cout << "static alloc : " << t.elapsed() << std::endl;
	}
	*/

	/*
	std::string text;

	while( std::getline( std::cin, text ) )
	{
		if( text == "exit" )
			break;

		std::cout << umtl::translator::translate( text, "en" ) << std::endl;
	}
	*/

/*
	typedef umtl::quantizer< char, 3, 256 > Quantizer;
	Quantizer quantizer;

	umtl::bmp bmp;

	bmp.load( "test.bmp" );

	quantizer.make( bmp.data(), bmp.size() );

	quantizer.save( "test.qaz" );

	quantizer.load( "test.qaz" );

	Quantizer::Samples & samples = quantizer.get();

	char * data = bmp.data();
	size_t cnt = 0;

	for( size_t i=0; i<samples.size(); ++i )
	{
		for( size_t d=0; d<Quantizer::_dimension; ++d )
			data[cnt++] = (char)( samples[i]->at(d));
	}

	bmp.save( "test2.bmp" );
	*/

	//umtl::memory_manager::get().free( umtl::memory_manager::get().alloc( 1024*1024*50 ) );

/*
	for(int i=0; i<20; ++i)
	{
		boost::timer t;

		//t.restart();

		//alloc_test< PoolAlloc, 1 >();

		//std::cout << "unit : " << t.elapsed() << std::endl;

		//t.restart();

		alloc_test< NormalAlloc, 1 >();

		std::cout << "normal : " << t.elapsed() << std::endl;
	}
	*/

/*
	umtl::bmp bmp2;
	bmp2.load( "test2.bmp" );

	umtl::tga_t tga( "test2.tga" );

	typedef umtl::webp::encoder<> WebpEncoder;

	WebpEncoder encoder;

	WebpEncoder::buffer buffer = encoder( (unsigned char *)tga.get(), tga.width(), tga.height(), umtl::webp::color_type::bgra, 75.0f );

	if( buffer.data() )
	{
		std::ofstream ofs( "test.webp", std::ios::out | std::ios::binary | std::ios::trunc );

		ofs.write( (char*)buffer.data(), buffer.size() );
	}

	umtl::bmp bmp;
	bmp.set( tga.get(), tga.width(), tga.height() );
	bmp.save( "test.bmp" );
	*/

/*
	struct Timer
	{
		~Timer() { std::cout << timer.elapsed() << std::endl; }

		boost::timer timer;
	};

	Timer timer;

	auto dispatch = [](int * i){ delete i; };

	umtl::distribution_port<int> port( dispatch );

	for( size_t i = 0; i < 1000000; ++i )
	{
		port.post( new int(i) );
		//dispatch( new int(i) );
	}*/

/*
	umtl::property_database< std::wstring > property_db( L"testdb.db" );

	//property_db.set( L"test", L"3322" );
	std::wcout << property_db.get( L"test" ) << std::endl;
	*/

	/*umtl::commandline::parser< std::wstring > parser;

	parser.Regist( L"--옵션,-옵", L"옵션 입니다.", umtl::commandline::parser<std::wstring>::MakeDefaults( 1, L"옵션디폴트 값." ) );

	std::wcout.imbue( std::locale("kor") );

	std::wcout << parser.Help() << std::endl;

	parser.Parse( L"-옵 디폴트아님" );

	std::wcout << parser.Get(L"-옵")->Values[0] << std::endl;*/

	

	//file_handler.cancel();

	/*
	boost::thread_group threads;

	for( size_t i=0; i<10; ++i)
	{
		threads.create_thread( []()
		{
			for( size_t i=0; i<10000; ++i )
			{
				void * m = umtl::memory_manager::get().alloc( (rand() % 10000) + 1 );
				umtl::memory_manager::get().free( m );
			}
		});
	}

	threads.join_all();
	*/


	


	/*
	for( size_t j=0; j<100; ++j )
	{
		static const size_t loop = 10000;

		static const size_t maxsize = 10000;

		test11();

		{
			boost::timer t;

			for( size_t i = 0; i<loop; ++i )
			{
				void * p = malloc( (rand()%maxsize) + 1 );
				free(p);
			}

			std::cout << t.elapsed() << std::endl;
		}

		{
			boost::timer t;

			for( size_t i = 0; i<loop; ++i )
			{
				char * p = new char[(rand()%maxsize)+1];
				delete[] p;
			}

			std::cout << t.elapsed() << std::endl;
		}
	}	*/

/*
	umtl::fast_buffer_t<char> buffer;

	buffer.resize(10);

	for( size_t i=0; i<10; ++i )
		buffer[i] = i;

	buffer.erase( 0, 1 );
	*/

	struct Test1
	{
		Test1( std::string const & str ) : str(str) {}

		std::string str;
	};

	umtl::smart_ptr< Test1 > test = make_smart_ptr( new Test1( "123123123" ) );
	

	char* public_key = umtl::ecies::public_key();
	char* private_key = umtl::ecies::private_key();

	std::wstring sample = L"애 닳도록 아름다워서 그만 고개를 떨구는 봄은 그런 계절입니다.\n\
						   숨이 턱턱 막히매 가슴을 치는 나와 당신께 이 봄은 겨울보다 더 시립니다.\n\
						   수많은 약속들이 하나 둘 햇빛에 산산히 흩어져 벗 꽃잎처럼 허공에 멍들고\n\
						   시선 가 닿는 곳 마다 떠뜨려 지는 저 눈부신 봄망울에\n\
						   잎술 깨물고 발 걷게 만드는 형벌같은 이 봄.";

	auto cryped = umtl::ecies::Instance().ecies_encrypt( public_key, (unsigned char*)sample.c_str(), sample.size() * sizeof(wchar_t) );
	
	size_t len = 0;
	auto decrypted = umtl::ecies::Instance().ecies_decrypt( private_key, cryped, &len );

	std::wcout.imbue( std::locale("kor") );

	std::wcout << (wchar_t*)decrypted << std::endl;

	return 0;
}
